import os
import uuid
import datetime

from PySide2.QtWidgets import *
from PySide2.QtCore import QFile, QStringListModel, Qt
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QFileDialog

import JsonGenerator
import Logger

import ExcelReader
import Util
from CoderDialog import CoderDialog
from ExcelData import ExcelData, TableData, FieldData, EData, SaveType, Platform, IndexType

from PublishDialog import PublishDialog
from SettingDialog import SettingDialog


class Excel2JsonWin:
    edata: EData
    """软件核心数据，记录使用什么excel表等信息"""

    listFile: QTableWidget
    selectedExcelData: ExcelData = None
    treeWidget: QTreeWidget

    logger: Logger

    currentTreeShowFile: str = ""
    """当前树正在展示的文件"""

    settingDialog: SettingDialog
    publishDialog: PublishDialog
    coderDialog: CoderDialog

    def __init__(self):
        super(Excel2JsonWin, self).__init__()

        # 从文件中加载UI定义
        qfile = QFile("data\\main.ui")
        qfile.open(QFile.ReadOnly)
        qfile.close()

        # 从UI定义中动态创建一个相应的窗口对象, 将其内部文件定义为self.ui.button
        self.ui = QUiLoader().load(qfile)

        # 把控件从UI编辑器拿下来指定类，让代码有提示
        self.listFile = self.ui.listFile
        self.treeWidget = self.ui.treeWidget
        # self.logs = self.ui.txtLog
        self.logger = Logger.Logger()
        self.logger.bindOuttext(self.ui.txtLog)

        # 引入3个弹出窗体
        self.settingDialog = SettingDialog()
        self.publishDialog = PublishDialog()
        self.coderDialog = CoderDialog()

        # 设置表头样式
        # self.listFile.edit
        self.listFile.setColumnCount(5)
        self.listFile.setHorizontalHeaderLabels(["Json文件", "表名", "所属Excel", "状态", "最后操作时间"])
        # self.listFile.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.listFile.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.listFile.horizontalHeader().setStyleSheet('''
            ::section {
                background-color: #FFEE99;
                border-style: solid;
                border-color: #BBBBBB;
                border-width: 1px;
                padding: 0px 0px;
                font-weight:bold;
                }''')

        # 注册菜单点击事件
        self.ui.menuOpen.triggered.connect(self.onBtnOpenFileClick)
        self.ui.menuSetting.triggered.connect(self.onMenuSettingClick)
        self.ui.menuQuit.triggered.connect(self.onQuitClick)
        self.ui.menuCoder.triggered.connect(self.onMenuCoderClick)  # 代码生成菜单
        self.ui.menuPublish.triggered.connect(self.onMenuPublishClick)  # 发布菜单
        self.ui.menuGitee.triggered.connect(self.onMenuGiteeClick)

        # 注册UI按钮绑定事件
        self.ui.btnOpenFile.clicked.connect(self.onBtnOpenFileClick)  # 导入excel
        self.ui.btnSave.clicked.connect(self.onBtnSaveClick)  # 保存列表
        self.ui.btnExport.clicked.connect(self.onBtnExportClick)  # 选中导出json
        self.ui.btnSelectAll.clicked.connect(self.onBtnSelectAllClick)  # 全选
        self.ui.btnSelectNone.clicked.connect(self.onBtnSelectNoneClick)  # 全不选
        self.ui.btnDelete.clicked.connect(self.onBtnDeleteClick)  # 删除选中
        self.ui.btnClear.clicked.connect(self.onBtnClearClick)  # 全部删除对象，等于新建
        self.ui.btnClearLogs.clicked.connect(self.onBtnClearLogsClick)  # 全部删除

        self.ui.btnMenuCoder.clicked.connect(self.onMenuCoderClick)  # 代码生成菜单
        self.ui.btnMenuPublish.clicked.connect(self.onMenuPublishClick)  # 发布菜单

        self.ui.listFile.itemClicked.connect(self.onListFileClick)  # 点击列表Item事件

        # 从记录文件读取之前的列表
        self.edata = EData()
        self.edata.restoreFromFile()
        self.refreshTable()

    def onQuitClick(self):
        exit()

    def onMenuSettingClick(self):
        self.settingDialog.show()

    def onMenuCoderClick(self):
        self.syncCheckStateToExcelData()  # 同步勾选状态
        self.coderDialog.show()
        # 调整窗口位置，不阻挡logs
        screen = QDesktopWidget().screenGeometry()
        size = self.coderDialog.ui.geometry()
        self.coderDialog.ui.move((screen.width() - size.width()) / 2, self.ui.y() + 50)

    def onMenuPublishClick(self):
        self.syncCheckStateToExcelData()  # 同步勾选状态
        self.publishDialog.show()

    def onBtnDeleteClick(self):
        """删除选中"""
        # 先删除表名
        for i in range(0, self.listFile.rowCount()):
            checkbox: QTableWidgetItem = self.listFile.item(i, 0)
            if checkbox.checkState() != Qt.Checked:
                # 没勾选不删除
                continue
            fileItem: QTableWidgetItem = self.listFile.item(i, 2)
            data: ExcelData = self.edata.excelDatas[fileItem.text()]
            if data is None:
                QMessageBox.information(self.ui, "警告", "勾选出错! 没对应文件名")
                continue
            table: TableData = data.tables[checkbox.text()]
            if table is None:
                QMessageBox.information(self.ui, "警告", "勾选出错! 没对应表名")
                continue
            del data.tables[checkbox.text()]
        # 发现没表的ExcelData也删除
        deleteList = []
        for key, value in self.edata.excelDatas.items():
            excel: ExcelData = value
            if len(excel.tables) < 1:
                deleteList.append(key)
        for key in deleteList:
            del self.edata.excelDatas[key]
        # 刷新列表
        self.refreshTable()

    def onBtnClearClick(self):
        """全部删除"""
        self.edata.clear()
        self.refreshTable()

    def onBtnClearLogsClick(self):
        """清除控制台内容"""
        self.logger.clear()

    def onBtnOpenFileClick(self):
        """选择Excel文件"""
        filePath = QFileDialog.getOpenFileName(self.ui, "选择引入的Excel配置文件", "./", "Excel Files (*.xls;*.xlsx)")
        # if filePath[0] == "": #没有选择文件，退出
        #     return
        if not os.path.isfile(filePath[0]):
            return
        print('File:', filePath)
        fileName = os.path.basename(filePath[0])
        self.logger.logNotice('加载Excel文件:' + fileName)
        data: ExcelData = ExcelData()
        data.fileName = fileName
        data.filePath = filePath[0]
        isSuccess = ExcelReader.importFile(data)
        if isSuccess:
            print(len(data.tables))
            self.logger.logSuccess('解析文件[' + fileName + ']结构: 成功！(*^▽^*)')
            self.edata.excelDatas[fileName] = data
            self.refreshTree(data, True)
            self.refreshTable()


        else:
            self.logger.logError('解析文件[' + fileName + ']结构: 失败！！')

    def onListFileClick(self, item: QTableWidgetItem):
        """点击excel文件列表"""
        print("QTable 您点击了：" + item.text() + " row:" + str(item.row()))
        # 根据点击事件去看当前选中的item的row，然后找出对应行元素
        jsonItem: QTableWidgetItem = self.listFile.item(item.row(), 0)
        fileItem: QTableWidgetItem = self.listFile.item(item.row(), 2)
        data: ExcelData = self.edata.excelDatas[fileItem.text()]
        self.refreshTree(data)
        self.syncCheckStateToExcelData()  # 同步勾选状态

    def onBtnSaveClick(self):
        result = self.edata.save(SaveType.ExcelAnalysis)
        if result:
            QMessageBox.information(self.ui, "提示", "已经保存列表!")
        else:
            QMessageBox.warning(self.ui, "提示", "保存列表失败！")

    def refreshTree(self, data: ExcelData, isForceRefresh: bool = False):
        """刷新左边树数据"""
        # 相同文件名则不刷新
        if self.currentTreeShowFile == data.fileName and isForceRefresh is False:
            return
        self.treeWidget.clear()
        mainItem = QTreeWidgetItem(None)
        mainItem.setText(0, data.fileName)  # Sheet名
        for tb in data.tables.values():
            table: TableData = tb
            tableItem = self.addTreeItem(mainItem, table.sheetName)
            self.addTreeItem(tableItem, "导出Json名:  " + table.jsonName)
            self.addTreeItem(tableItem, "数据起始行:  " + str(table.fieldDataRowIndex))
            fieldItem = self.addTreeItem(tableItem, "字段总数:  " + str(len(table.fields)))
            for field in table.fields:
                fieldNameItem: QTreeWidgetItem
                detalStr: str = field.fieldName + " [" + field.fieldType.name + "] " + " -->" + field.fieldKey + ""
                if field.canNotEmpty:
                    detalStr = "* " + detalStr
                fieldNameItem = self.addTreeItem(fieldItem, detalStr)
                self.addTreeItem(fieldNameItem, "约束:  " + field.fieldRestrain)
            loadCfgItem = self.addTreeItem(tableItem, "加载配置:" + str(len(table.loadConfigs)))
            for config in table.loadConfigs:
                # 加载平台与主键
                detail: str = ""
                strMultKey: str = ""
                for mk in config.keyFields:
                    strMultKey += mk.fieldKey + ", "
                strMultKey = strMultKey.strip(", ")
                if config.type is IndexType.List:
                    detail = " -> 主键/非空列[" + strMultKey + "]"
                else:
                    detail = " -> 主键[" + strMultKey + "]"
                loadCfgItemDetail = self.addTreeItem(loadCfgItem, "" + config.type.name + detail)
                strPlatforms: str = ""
                for val in config.exportPlatforms.values():
                    platform: Platform = val
                    strPlatforms += platform.name + " "
                self.addTreeItem(loadCfgItemDetail, "导出代码:  " + strPlatforms)
                self.addTreeItem(loadCfgItemDetail, "组别：" + config.group)
                if len(config.loadRelations) > 0:
                    loadCfgRelation = self.addTreeItem(loadCfgItemDetail, "关联加载：" + str(len(config.loadRelations)))
                    strRelation:str = ""
                    for realation in config.loadRelations:
                        self.addTreeItem(loadCfgRelation, realation)
                # 加载字段关联
                if len(config.unions) > 0:
                    unionItem = self.addTreeItem(loadCfgItem, "字段关联:    " + str(len(config.unions)))
                    for union in config.unions:
                        self.addTreeItem(unionItem, union.myKey + " >> " + union.unionTableName + "->" + union.unionKey)




        # 把梳理出来的树添加到根节点
        self.treeWidget.insertTopLevelItems(0, [mainItem])
        mainItem.setExpanded(True)  # 展开第一个节点
        # self.treeWidget.expandAll() #展开所有节点
        self.currentTreeShowFile = data.fileName

    def addTreeItem(self, parent: QTreeWidgetItem, text: str):
        item = QTreeWidgetItem(parent)
        item.setText(0, text)
        parent.addChild(item)
        return item

    def refreshTable(self):
        """刷新右边表格数据"""
        # 开始加载数据
        self.listFile.setRowCount(999)
        count: int = 0
        for fKey, fData1 in self.edata.excelDatas.items():
            fData: ExcelData = fData1
            for tKey, tData in fData.tables.items():
                tbData: TableData = tData
                itemSheet: QTableWidgetItem = QTableWidgetItem(tbData.sheetName)
                itemFilename: QTableWidgetItem = QTableWidgetItem(fData.fileName)
                itemTime: QTableWidgetItem
                if tbData.lastExecuteTime is not None:
                    itemTime = QTableWidgetItem(Util.getDateTimeString(tbData.lastExecuteTime))
                else:
                    itemTime = QTableWidgetItem("")
                # 插入单选框
                checkBox = QTableWidgetItem(tbData.jsonName)
                # 设置单选框为选中
                if tbData.isListChecked:
                    checkBox.setCheckState(Qt.Checked)
                else:
                    checkBox.setCheckState(Qt.Unchecked)

                self.listFile.setItem(count, 0, checkBox)
                # self.listFile.setItem(i, 0, item1)
                self.listFile.setItem(count, 1, itemSheet)
                self.listFile.setItem(count, 2, itemFilename)
                self.listFile.setItem(count, 4, itemTime)

                count += 1
        self.listFile.setRowCount(count)

    def syncCheckStateToExcelData(self):
        """同步右边表格勾选状态到记录库"""
        print("check")
        for i in range(0, self.listFile.rowCount()):
            checkbox: QTableWidgetItem = self.listFile.item(i, 0)
            fileItem: QTableWidgetItem = self.listFile.item(i, 2)
            data: ExcelData = self.edata.excelDatas[fileItem.text()]
            if data is None:
                QMessageBox.information(self.ui, "警告", "勾选出错! 没对应文件名")
                continue
            table: TableData = data.tables[checkbox.text()]
            if table is None:
                QMessageBox.information(self.ui, "警告", "勾选出错! 没对应表名")
                continue
            if checkbox.checkState() == Qt.Checked:
                table.isListChecked = True
            else:
                table.isListChecked = False

    def onBtnExportClick(self):
        """导出选中的excel表"""
        exportTime = datetime.datetime.now()
        exportVersion = uuid.uuid1()
        result = JsonGenerator.exportFile(str(exportVersion), exportTime)
        result2 = JsonGenerator.exportFileSetting(str(exportVersion), exportTime)
        if result and result2:
            self.refreshTable()  # 刷新table更新状态
            Util.openFilePath(self.edata.setting.defDirJsonFile)
            # QMessageBox.information(self.ui, "提示", "已经全部导出为JSON数据表")
            self.logger.logAllDone("勾选项目已经全部导出为JSON数据表！(✪ω✪)")

    def onBtnSelectAllClick(self):
        """全选"""
        for i in range(0, self.listFile.rowCount()):
            checkbox: QTableWidgetItem = self.listFile.item(i, 0)
            checkbox.setCheckState(Qt.Checked)
        self.syncCheckStateToExcelData()

    def onBtnSelectNoneClick(self):
        """全不选"""
        for i in range(0, self.listFile.rowCount()):
            checkbox: QTableWidgetItem = self.listFile.item(i, 0)
            checkbox.setCheckState(Qt.Unchecked)
        self.syncCheckStateToExcelData()

    def onMenuGiteeClick(self):
        QMessageBox.information(self.ui, "提示",
                                "An open source project\nAuthor:Seraph.yang\nGitee： https://gitee.com/seraph2047/excel2json")


if __name__ == '__main__':
    app = QApplication([])
    w = Excel2JsonWin()
    w.ui.show()
    app.exec_()
